Skip to content

S01-15 JavaSE-包装类

[TOC]

包装类

包装类分类

基本数据类型包装类
booleanBoolean
charCharacter
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble

包装类和基本数据的转换

  • 装箱:基本类型 → 包装类型
  • 拆箱:包装类型 → 基本类型
  • JDK5后支持自动装箱/拆箱(底层调用valueOf()和xxxValue()方法)

案例演示(Integer01.java)

java
package com.hspedu.wrapper;

public class Integer01 {
    public static void main(String[] args) {
        // JDK5前:手动装箱/拆箱
        // 手动装箱
        int n1 = 100;
        Integer integer = new Integer(n1);
        Integer integer1 = Integer.valueOf(n1);

        // 手动拆箱
        int i = integer.intValue();

        // JDK5后:自动装箱/拆箱
        int n2 = 200;
        Integer integer2 = n2; // 自动装箱(底层Integer.valueOf(n2))
        int n3 = integer2; // 自动拆箱(底层integer2.intValue())
    }
}

包装类型和String类型的相互转换

java
package com.hspedu.wrapper;

public class WrapperVSString {
    public static void main(String[] args) {
        // 包装类 -> String
        Integer i = 100;
        String str1 = i + ""; // 方式1
        String str2 = i.toString(); // 方式2
        String str3 = String.valueOf(i); // 方式3

        // String -> 包装类
        String str4 = "12345";
        Integer i2 = Integer.parseInt(str4); // 方式1(推荐)
        Integer i3 = new Integer(str4); // 方式2(不推荐)
    }
}

Integer和Character类的常用方法

java
package com.hspedu.wrapper;

public class WrapperMethod {
    public static void main(String[] args) {
        // Integer常用方法
        System.out.println(Integer.MIN_VALUE); // 最小值
        System.out.println(Integer.MAX_VALUE); // 最大值

        // Character常用方法
        System.out.println(Character.toUpperCase('a')); // 转大写
        System.out.println(Character.isDigit('a')); // 是否为数字
        System.out.println(Character.isLetter('a')); // 是否为字母
        System.out.println(Character.isUpperCase('a')); // 是否为大写
        System.out.println(Character.isLowerCase('a')); // 是否为小写
        System.out.println(Character.isWhitespace(' ')); // 是否为空格
    }
}

Integer类面试题

java
package com.hspedu.wrapper;

public class WrapperExercise02 {
    public static void main(String[] args) {
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j); // False(不同对象)

        Integer m = 1; // 底层Integer.valueOf(1)
        Integer n = 1;
        System.out.println(m == n); // True(-128~127缓存)

        Integer x = 128;
        Integer y = 128;
        System.out.println(x == y); // False(超出缓存范围)
    }
}

缓存机制说明

  • IntegerCache缓存-128~127之间的整数
  • 超出范围时,直接new Integer对象

String类

String类的核心特性

  1. String对象用于保存字符串(字符序列)
  2. 字符串常量用双引号括起(如"hello")
  3. 字符编码:Unicode(每个字符占2字节)
  4. 实现接口:Serializable(可串行化)、Comparable(可比较)
  5. String是final类,不能被继承
  6. 底层存储:private final char value[](value数组不可变)

创建String对象的两种方式

  1. 直接赋值String s = "hspedu";
    • 先从常量池查找,有则直接指向,无则创建后指向
  2. 调用构造器String s = new String("hspedu");
    • 先在堆中创建对象,再指向常量池的字符串

案例演示(String01.java)

java
package com.hspedu.string_;

public class String01 {
    public static void main(String[] args) {
        // 构造器创建
        String s1 = new String();
        String s2 = new String("hspedu");
        char[] chars = {'h','s','p','e','d','u'};
        String s3 = new String(chars);
        String s4 = new String(chars, 0, 3); // 从索引0开始,取3个字符

        // 直接赋值
        String s5 = "hspedu";
    }
}

课堂测试题

java
package com.hspedu.string_;

public class StringExercise01 {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        System.out.println(a.equals(b)); // True(内容相同)
        System.out.println(a == b); // True(指向同一常量池对象)
    }
}

测试题2 StringExercise02.java

java
String a = new String("abc");
String b = new String("abc");
System.out.println(a.equals(b));// T
System.out.println(a == b); // F

测试题3 StringExercise03.java(2min思考)

java
String a = "hsp";// a指向常量池的"hsp"
String b = new String("hsp");// b指向堆中对象
System.out.println(a.equals(b));// T
System.out.println(a == b.intern());// T //intern方法自己先查看API
System.out.println(b == b.intern()); // F
System.out.println(a == b); // F

知识点:

当调用intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此String对象的引用。

老韩解读: (1) b.intern()方法最终返回的是常量池的地址(对象)

对应的示意图: 第544页

测试题4 StringExercise04.java(2min)

java
String s1 = "hspedu"; // 指向常量池"hspedu"
String s2 = "java";// 指向常量池"java"
String s3 = new String("java");// 指向堆中对象
String s4 = "java";// 指向常量池"java"
System.out.println(s2 == s3);// F
System.out.println(s2 == s4); // T
System.out.println(s2.equals(s3));// T
System.out.println(s1 == s2); // F

第545页

测试题5 StringExercise05.java(5min思考)

java
Person p1 = new Person();
p1.name = "hspedu";
Person p2 = new Person();
p2.name = "hspedu";
System.out.println(p1.name.equals(p2.name));// 比较内容:True
System.out.println(p1.name == p2.name);// T
System.out.println(p1.name == "hspedu"); // T

String s1 = new String("bcde");
String s2 = new String("bcde");
System.out.println(s1 == s2); // False
// 请画出内存布局图

第546页

13.3 字符串的特性

说明 StringExercise06.java

  1. String是一个final类,代表不可变的字符序列
  2. 字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的。
java
String s1 = "hello";
s1 = "haha";
// 1min 1.以下语句创建了几个对象?画出内存布局图。
// 创建了2个对象.

面试题

  1. 题1 String a = "hello" + "abc"; 创建了几个对象?(1min)

    • 编译器优化:等价于 String a = "helloabc";
    • 结论:只有1个对象。
  2. 题2 String Exercise08.java(1min思考)

java
String a = "hello";// 创建a对象
String b = "abc";// 创建b对象
String c = a + b;
// 创建了几个对象?画出内存图?

关键分析:String c = a + b; 底层执行流程

java
StringBuilder sb = new StringBuilder();
sb.append(a);
sb.append(b);
// sb是在堆中,并且append是在原来字符串的基础上追加的

老韩小结

  • 常量相加(如"ab"+"cd"):看常量池
  • 变量相加(如a + b):在堆中创建StringBuilder对象处理
  • 结论:一共创建3个对象
  1. 题3 StringExercise09.java
java
String s1 = "hspedu"; // s1指向池中的"hspedu"
String s2 = "java";// s2指向池中的"java"
String s5 = "hspedujava"; // s5指向池中的 "hspedujava"
String s6 = (s1 + s2).intern();// s6指向池中的 "hspedujava"
System.out.println(s5 == s6);// T
System.out.println(s5.equals(s6));// T

第548页

测试题 StringExercise10.java

java
public class Test1{
    String str = new String("hsp");
    final char[] ch ={'j','a','v','a'};
    public void change(String str, char ch[]){
        str = "java";
        ch[0] = 'h';
    }
    public static void main(String[] args) {
        Test1 ex = new Test1();
        ex.change(ex.str, ex.ch);
        System.out.print(ex.str + "and ");
        System.out.println(ex.ch);
    }
}
// 思考,认真看,仔细想3min

运行结果:hsp and hava

第549页

13.4 String 类的常见方法

说明

String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此java设计者还提供了StringBuilder和StringBuffer来增强String的功能,并提高效率。[后面我们还会详细介绍StringBuilder和StringBuffer]

java
// 看看这段代码
String s = new String("");
for(int i=0;i<80000; i++){
    s += "hello";
}

String 类的常见方法一览

方法名说明
equals区分大小写,判断内容是否相等
equalsIgnoreCase忽略大小写的判断内容是否相等
length获取字符的个数,字符串的长度
indexOf获取字符在字符串中第1次出现的索引,索引从0开始,如果找不到,返回-1
lastIndexOf获取字符在字符串中最后1次出现的索引,索引从0开始,如找不到,返回-1
substring截取指定范围的子串
trim去前后空格
charAt获取某索引处的字符,注意不能使用Str[index]这种方式
toUpperCase转换成大写
toLowerCase转换成小写
concat拼接字符串
replace替换字符串中的字符
split分割字符串,对于某些分割字符,需要转义比如|、\等
compareTo比较两个字符串的大小
toCharArray转换成字符数组
format格式字符串,%s字符串、%c字符、%d整型、%.2f浮点型

方法演示1:StringMethod01.java

java
package com.hspedu.string_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringMethod01 {
    public static void main(String[] args) {
        // 1. equals 前面已经讲过了. 比较内容是否相同,区分大小写
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.equals(str2));// false

        // 2.equalsIgnoreCase 忽略大小写的判断内容是否相等
        String username = "johN";
        if ("john".equalsIgnoreCase(username)) {
            System.out.println("Success!");
        } else {
            System.out.println("Failure!");
        }

        // 3.length 获取字符的个数,字符串的长度
        System.out.println("韩顺平".length());// 3

        // 4.indexOf 获取字符在字符串对象中第一次出现的索引,索引从0 开始,如果找不到,返回-1
        String s1 = "wer@terwe@g";
        int index = s1.indexOf('@');
        System.out.println(index);// 3
        System.out.println("weIndex=" + s1.indexOf("we"));// 0

        // 5.lastIndexOf 获取字符在字符串中最后一次出现的索引,索引从0 开始,如果找不到,返回-1
        s1 = "wer@terwe@g@";
        index = s1.lastIndexOf('@');
        System.out.println(index);// 11
        System.out.println("ter 的位置=" + s1.lastIndexOf("ter"));// 4

        // 6.substring 截取指定范围的子串
        String name = "hello,张三";
        // 下面name.substring(6) 从索引6 开始截取后面所有的内容
        System.out.println(name.substring(6));// 张三
        // name.substring(0,5)表示从索引0 开始截取,截取到索引5-1=4 位置
        System.out.println(name.substring(2, 5));// llo
    }
}

方法演示2:StringMethod02.java

java
package com.hspedu.string_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringMethod02 {
    public static void main(String[] args) {
        // 1.toUpperCase 转换成大写
        String s = "heLLo";
        System.out.println(s.toUpperCase());// HELLO

        // 2.toLowerCase
        System.out.println(s.toLowerCase());// hello

        // 3.concat 拼接字符串
        String s1 = "宝玉";
        s1 = s1.concat("林黛玉").concat("薛宝钗").concat("together");
        System.out.println(s1);// 宝玉林黛玉薛宝钗together

        // 4.replace 替换字符串中的字符
        s1 = "宝玉and 林黛玉林黛玉林黛玉";
        // 在s1 中,将所有的林黛玉替换成薛宝钗
        // 注意对s1 没有任何影响
        String s11 = s1.replace("宝玉", "jack");
        System.out.println(s1);// 宝玉and 林黛玉林黛玉林黛玉
        System.out.println(s11);// jack and 林黛玉林黛玉林黛玉

        // 5.split 分割字符串, 对于某些分割字符,我们需要转义比如| \\等
        String poem = "锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦";
        // 老韩解读:
        // 1. 以, 为标准对poem 进行分割, 返回一个数组
        String[] split = poem.split(",");
        System.out.println("==分割后内容===");
        for (int i = 0; i < split.length; i++) {
            System.out.println(split[i]);
        }

        // 分割文件路径
        poem = "E:\\aaa\\bbb";
        split = poem.split("\\\\");
        for (int i = 0; i < split.length; i++) {
            System.out.println(split[i]);
        }

        // 6.toCharArray 转换成字符数组
        s = "happy";
        char[] chs = s.toCharArray();
        for (int i = 0; i < chs.length; i++) {
            System.out.println(chs[i]);
        }

        // 7.compareTo 比较两个字符串的大小
        // 老韩解读
        // (1) 如果长度相同,并且每个字符也相同,就返回0
        // (2) 如果长度相同或者不相同,但是在进行比较时,可以区分大小 就返回 c1 - c2
        // (3) 如果前面的部分都相同,就返回str1.len - str2.len
        String a = "jcck";// len = 4
        String b = "jack";// len = 4
        System.out.println(a.compareTo(b)); // 返回值是'c' - 'a' = 2

        // 8.format 格式字符串
        /* 占位符有:
         * %s 字符串、%c 字符、%d 整型、%.2f 浮点型
         */
        String name = "john";
        int age = 10;
        double score = 56.857;
        char gender = '男';

        // 传统拼接方式
        String info = "我的姓名是" + name + "年龄是" + age + ",成绩是" + score + "性别是" + gender + "。希望大家喜欢我!";
        System.out.println(info);

        // format方式
        String formatStr = "我的姓名是%s 年龄是%d,成绩是%.2f 性别是%c.希望大家喜欢我!";
        String info2 = String.format(formatStr, name, age, score, gender);
        System.out.println("info2=" + info2);
    }
}

第554页

13.5 StringBuffer 类

基本介绍

java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删。很多方法与String相同,但StringBuffer是可变长度的。StringBuffer是一个容器。

java
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
    // A cache of the last value returned by toString. Cleared whenever the StringBuffer is modified.
}

StringBuffer01.java

java
package com.hspedu.stringbuffer_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringBuffer01 {
    public static void main(String[] args) {
        // 老韩解读
        // 1. StringBuffer 的直接父类是AbstractStringBuilder
        // 2. StringBuffer 实现了Serializable, 即StringBuffer 的对象可以串行化
        // 3. 在父类中 AbstractStringBuilder 有属性char[] value,不是final
        // 该value 数组存放字符串内容,存放在堆中的
        // 4. StringBuffer 是一个final 类,不能被继承
        // 5. 因为StringBuffer 字符内容是存在char[] value, 所有在变化(增加/删除)
        // 不用每次都更换地址(即不是每次创建新对象),所以效率高于String
        StringBuffer stringBuffer = new StringBuffer("hello");
    }
}

第556页

String VS StringBuffer

特性StringStringBuffer
存储内容字符串常量字符串变量
可变性不可变(private final char value[])可变(char[] value,存放在堆)
效率较低(每次更新更换地址)较高(更新内容不换地址)

String 和StringBuffer 相互转换

StringAndStringBuffer.java

java
package com.hspedu.stringbuffer_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringAndStringBuffer {
    public static void main(String[] args) {
        // String-->StringBuffer
        String str = "hello tom";

        // 方式1 使用构造器
        // 注意:返回的才是StringBuffer 对象,对str 本身没有影响
        StringBuffer stringBuffer = new StringBuffer(str);

        // 方式2 使用的是append 方法
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1 = stringBuffer1.append(str);

        // StringBuffer ->String
        StringBuffer stringBuffer3 = new StringBuffer("韩顺平教育");

        // 方式1 使用StringBuffer 提供的toString 方法
        String s = stringBuffer3.toString();

        // 方式2: 使用构造器来搞定
        String s1 = new String(stringBuffer3);
    }
}

第557页

StringBuffer 类常见方法

StringBufferMethod.java

java
package com.hspedu.stringbuffer_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringBufferMethod {
    public static void main(String[] args) {
        StringBuffer s = new StringBuffer("hello");

        // 增
        s.append("张三丰");// "hello张三丰"
        s.append(',');// "hello张三丰,"
        s.append("赵敏").append(100).append(true).append(10.5);// "hello张三丰,赵敏100true10.5"
        System.out.println(s);// "hello张三丰,赵敏100true10.5"

        // 删
        /*
         * 删除索引为>=start && <end 处的字符
         * 解读: 删除11~14 的字符[11, 14)
         */
        s.delete(11, 14);
        System.out.println(s);// "hello张三丰,赵敏true10.5"

        // 改
        // 老韩解读,使用周芷若替换索引9-11 的字符[9,11)
        s.replace(9, 11, "周芷若");
        System.out.println(s);// "hello张三丰,周芷若true10.5"

        // 查找指定的子串在字符串第一次出现的索引,如果找不到返回-1
        int indexOf = s.indexOf("张三丰");
        System.out.println(indexOf);// 6

        // 插
        // 老韩解读,在索引为9 的位置插入"赵敏",原来索引为9 的内容自动后移
        s.insert(9, "赵敏");
        System.out.println(s);// "hello张三丰,赵敏周芷若true10.5"

        // 长度
        System.out.println(s.length());// 22
    }
}

第559页

StringBuffer 类课堂测试题1 StringBufferExercise01.java

java
package com.hspedu.stringbuffer_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringBufferExercise01 {
    public static void main(String[] args) {
        String str = null;// ok
        StringBuffer sb = new StringBuffer(); // ok
        sb.append(str);// 需要看源码, 底层调用的是AbstractStringBuilder 的appendNull
        System.out.println(sb.length());// 4
        System.out.println(sb);// null

        // 下面的构造器,会抛出NullPointerException
        StringBuffer sb1 = new StringBuffer(str);// 看底层源码super(str.length() + 16);
        System.out.println(sb1);
    }
}

第560页

StringBuffer 类课后练习2 StringBufferExercise02.java

题目要求

输入商品名称和商品价格,要求打印效果示例:

商品名 商品价格
手机 123,564.59

比如价格3,456,789.88,要求:价格的小数点前面每三位用逗号隔开,在输出。

思路分析

  1. 定义一个Scanner 对象,接收用户输入的价格(String)
  2. 希望使用到StringBuffer 的insert,需要将String 转成StringBuffer
  3. 找到小数点的索引,然后在该位置的前3位插入逗号,循环处理

代码实现

java
package com.hspedu.stringbuffer_;

import java.util.Scanner;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringBufferExercise02 {
    public static void main(String[] args) {
        String price = "8123564.59";// 测试数据
        StringBuffer sb = new StringBuffer(price);

        // 循环插入逗号
        for (int i = sb.lastIndexOf(".") - 3; i > 0; i -= 3) {
            sb = sb.insert(i, ",");
        }

        System.out.println(sb);// 8,123,564.59
    }
}

第562页

13.6 StringBuilder 类

基本介绍

  1. 一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder不是线程安全)。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。
  2. 在StringBuilder上的主要操作是append和insert方法,可重载这些方法,以接受任意类型的数据。
java
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
}

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    // The value is used for character storage.
    char[] value;
}

StringBuilder01.java

java
package com.hspedu.stringbuilder_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringBuilder01 {
    public static void main(String[] args) {
        // 老韩解读
        // 1. StringBuilder 继承AbstractStringBuilder 类
        // 2. 实现了Serializable ,说明StringBuilder 对象是可以串行化(对象可以网络传输,可以保存到文件)
        // 3. StringBuilder 是final 类, 不能被继承
        // 4. StringBuilder 对象字符序列仍然是存放在其父类AbstractStringBuilder 的char[] value;
        // 因此,字符序列是堆中
        // 5. StringBuilder 的方法,没有做互斥的处理,即没有synchronized 关键字,因此在单线程的情况下使用
        StringBuilder stringBuilder = new StringBuilder();
    }
}

第564页

StringBuilder 常用方法

StringBuilder 和StringBuffer 均代表可变的字符序列,方法是完全一样的,使用方式相同(参考StringBuffer)。

String、StringBuffer 和StringBuilder 的比较

特性StringStringBufferStringBuilder
可变性不可变字符序列可变字符序列可变字符序列
线程安全-安全(有synchronized)不安全
效率最低中等最高
复用率--

效率测试 StringVsStringBufferVsStringBuilder.java

java
package com.hspedu.stringbuilder_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class StringVsStringBufferVsStringBuilder {
    public static void main(String[] args) {
        long startTime = 0L;
        long endTime = 0L;

        // StringBuffer 测试
        StringBuffer buffer = new StringBuffer("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer 的执行时间:" + (endTime - startTime));

        // StringBuilder 测试
        StringBuilder builder = new StringBuilder("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder 的执行时间:" + (endTime - startTime));

        // String 测试
        String text = "";
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {
            text = text + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String 的执行时间:" + (endTime - startTime));
    }
}

效率结论:StringBuilder > StringBuffer > String

选择原则

  1. 如果字符串存在大量的修改操作,一般使用StringBuffer 或StringBuilder
  2. 如果字符串存在大量的修改操作,并在单线程的情况,使用StringBuilder
  3. 如果字符串存在大量的修改操作,并在多线程的情况,使用StringBuffer
  4. 如果字符串很少修改,被多个对象引用,使用String,比如配置信息等

第567页

13.7 Math 类

基本介绍

Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。

方法一览(均为静态方法)

方法说明
abs(double a)返回double 值的绝对值
abs(float a)返回float 值的绝对值
abs(int a)返回int 值的绝对值
abs(long a)返回long 值的绝对值
acos(double a)返回一个值的反余弦,返回的角度范围在0.0到pi之间
asin(double a)返回一个值的反正弦,返回的角度范围在-pi/2 到pi/2 之间
atan(double a)返回一个值的反正切,返回的角度范围在-pi/2 到pi/2 之间
atan2(double y, double x)将矩形坐标(x,y)转换成极坐标(r,theta),返回所得角theta
cbrt(double a)返回double 值的立方根
ceil(double a)向上取整,返回>=该参数的最小整数(转成double)
floor(double a)向下取整,返回<=该参数的最大整数(转成double)
pow(double a, double b)返回a 的b 次方
round(double a)四舍五入
sqrt(double a)返回double 值的平方根
random()返回0 <= x < 1 之间的一个随机小数
max(int a, int b)返回两个int 值的最大值
min(int a, int b)返回两个int 值的最小值

Math 类常见方法应用案例

MathMethod.java

java
package com.hspedu.math_;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class MathMethod {
    public static void main(String[] args) {
        // 1.abs 绝对值
        int abs = Math.abs(-9);
        System.out.println(abs);// 9

        // 2.pow 求幂
        double pow = Math.pow(2, 4);// 2 的4 次方
        System.out.println(pow);// 16.0

        // 3.ceil 向上取整
        double ceil = Math.ceil(3.9);
        System.out.println(ceil);// 4.0

        // 4.floor 向下取整
        double floor = Math.floor(4.001);
        System.out.println(floor);// 4.0

        // 5.round 四舍五入
        long round = Math.round(5.51);
        System.out.println(round);// 6

        // 6.sqrt 求开方
        double sqrt = Math.sqrt(9.0);
        System.out.println(sqrt);// 3.0

        // 7.random 求随机数
        // 需求:获取a-b 之间的一个随机整数(a,b 均为整数),比如a=2, b=7
        // 公式: (int)(a + Math.random() * (b - a + 1))
        for (int i = 0; i < 100; i++) {
            System.out.println((int) (2 + Math.random() * (7 - 2 + 1)));
        }

        // 8.max , min 返回最大值和最小值
        int min = Math.min(1, 9);
        int max = Math.max(45, 90);
        System.out.println("min=" + min);
        System.out.println("max=" + max);
    }
}

第569页

13.8 Arrays 类

Arrays 类常见方法应用案例

Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)。

方法说明
toString(arr)返回数组的字符串形式
sort(arr)自然排序
sort(arr, Comparator)定制排序
binarySearch(arr, key)通过二分搜索法进行查找,要求必须排好序
copyOf(arr, length)数组元素的复制
fill(arr, value)数组元素的填充
equals(arr1, arr2)比较两个数组元素内容是否完全一致
asList(values)将一组值,转换成list

案例1:ArraysMethod01.java(toString、sort)

java
package com.hspedu.arrays_;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class ArraysMethod01 {
    public static void main(String[] args) {
        Integer[] integers = {1, 20, 90};
        // 直接使用Arrays.toString 方法,显示数组
        System.out.println(Arrays.toString(integers));// [1, 20, 90]

        // 演示sort 方法的使用
        Integer arr[] = {1, -1, 7, 0, 89};
        System.out.println("排序前=" + Arrays.toString(arr));

        // 定制排序(从大到小)
        Arrays.sort(arr, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Integer i1 = (Integer) o1;
                Integer i2 = (Integer) o2;
                return i2 - i1;
            }
        });

        System.out.println("排序后=" + Arrays.toString(arr));// [89, 7, 1, 0, -1]
    }
}

案例2:ArraysSortCustom.java(冒泡+定制排序)

java
package com.hspedu.arrays_;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class ArraysSortCustom {
    public static void main(String[] args) {
        int[] arr = {1, -1, 8, 0, 20};
        // 使用冒泡+定制排序
        bubble02(arr, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                int i1 = (Integer) o1;
                int i2 = (Integer) o2;
                return i2 - i1;// 从大到小
            }
        });
        System.out.println("==定制排序后的情况==");
        System.out.println(Arrays.toString(arr));
    }

    // 普通冒泡排序(从小到大)
    public static void bubble01(int[] arr) {
        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    // 冒泡+定制排序
    public static void bubble02(int[] arr, Comparator c) {
        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                // 数组排序由c.compare(arr[j], arr[j + 1])返回的值决定
                if (c.compare(arr[j], arr[j + 1]) > 0) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }
}

案例3:ArraysMethod02.java(binarySearch、copyOf、fill、equals、asList)

java
package com.hspedu.arrays_;

import java.util.Arrays;
import java.util.List;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class ArraysMethod02 {
    public static void main(String[] args) {
        Integer[] arr = {1, 2, 90, 123, 567};

        // 1.binarySearch 二叉查找(数组必须有序)
        int index = Arrays.binarySearch(arr, 567);
        System.out.println("index=" + index);// 4

        // 2.copyOf 数组复制
        Integer[] newArr = Arrays.copyOf(arr, arr.length);
        System.out.println("==拷贝执行完毕后==");
        System.out.println(Arrays.toString(newArr));// [1, 2, 90, 123, 567]

        // 3.fill 数组填充
        Integer[] num = new Integer[]{9, 3, 2};
        Arrays.fill(num, 99);
        System.out.println("==num 数组填充后==");
        System.out.println(Arrays.toString(num));// [99, 99, 99]

        // 4.equals 比较两个数组
        Integer[] arr2 = {1, 2, 90, 123};
        boolean equals = Arrays.equals(arr, arr2);
        System.out.println("equals=" + equals);// false

        // 5.asList 转成list
        List asList = Arrays.asList(2, 3, 4, 5, 6, 1);
        System.out.println("asList=" + asList);
        System.out.println("asList 的运行类型" + asList.getClass());// class java.util.Arrays$ArrayList
    }
}

第578页

Arrays 类课堂练习 ArrayExercise.java

题目要求

自定义Book类,里面包含name和price,按price排序(从大到小)。要求使用两种方式排序,有一个Book[] books=4本书对象。使用传递实现Comparator接口匿名内部类(定制排序),完成:

  1. 按price从大到小
  2. 按price从小到大
  3. 按书名长度从大到小

代码实现

java
package com.hspedu.arrays_;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class ArrayExercise {
    public static void main(String[] args) {
        Book[] books = new Book[4];
        books[0] = new Book("红楼梦", 100);
        books[1] = new Book("金瓶梅新", 90);
        books[2] = new Book("青年文摘20年", 5);
        books[3] = new Book("java从入门到放弃~", 300);

        // (1)price 从大到小
        Arrays.sort(books, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Book book1 = (Book) o1;
                Book book2 = (Book) o2;
                double priceVal = book2.getPrice() - book1.getPrice();
                if (priceVal > 0) {
                    return 1;
                } else if (priceVal < 0) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
        System.out.println("===按price从大到小===");
        System.out.println(Arrays.toString(books));

        // (2)price 从小到大
        Arrays.sort(books, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Book book1 = (Book) o1;
                Book book2 = (Book) o2;
                double priceVal = book2.getPrice() - book1.getPrice();
                if (priceVal > 0) {
                    return -1;
                } else if (priceVal < 0) {
                    return 1;
                } else {
                    return 0;
                }
            }
        });
        System.out.println("===按price从小到大===");
        System.out.println(Arrays.toString(books));

        // (3)按书名长度从大到小
        Arrays.sort(books, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Book book1 = (Book) o1;
                Book book2 = (Book) o2;
                // 按书名长度排序
                return book2.getName().length() - book1.getName().length();
            }
        });
        System.out.println("===按书名长度从大到小===");
        System.out.println(Arrays.toString(books));
    }
}

class Book {
    private String name;
    private double price;

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

第583页

13.9 System 类

System 类常见方法和案例

方法说明
exit(int status)退出当前程序,0表示正常退出
arraycopy(src, srcPos, dest, destPos, length)复制数组元素
currentTimeMillis()返回当前时间距离1970-1-1的毫秒数
gc()运行垃圾回收机制

System_.java

java
package com.hspedu.system_;

import java.util.Arrays;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class System_ {
    public static void main(String[] args) {
        // 1.exit 退出当前程序
        System.out.println("ok1");
        // System.exit(0);// 退出程序,后续代码不执行
        System.out.println("ok2");

        // 2.arraycopy 复制数组
        int[] src = {1, 2, 3};
        int[] dest = new int[3];// dest 当前是{0,0,0}
        /*
         * 参数说明:
         * src: 源数组
         * srcPos: 从源数组的哪个索引位置开始拷贝
         * dest: 目标数组
         * destPos: 把源数组的数据拷贝到目标数组的哪个索引
         * length: 从源数组拷贝多少个数据到目标数组
         */
        System.arraycopy(src, 0, dest, 0, src.length);
        System.out.println("dest=" + Arrays.toString(dest));// [1, 2, 3]

        // 3.currentTimeMillis 返回当前时间戳
        System.out.println(System.currentTimeMillis());
    }
}

第585页

13.10 BigInteger 和BigDecimal 类

介绍

类名应用场景
BigInteger适合保存比较大的整型(long不够用时)
BigDecimal适合保存精度更高的浮点型(double不够用时)

常见方法

方法说明
add
subtract
multiply
divide除(BigDecimal需指定精度)

BigInteger_.java

java
package com.hspedu.bignum;

import java.math.BigInteger;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class BigInteger_ {
    public static void main(String[] args) {
        // long 不够用的场景
        long l = 2378888889999999999L;
        System.out.println("l=" + l);

        BigInteger bigInteger = new BigInteger("23788888899999999999999999999");
        BigInteger bigInteger2 = new BigInteger("10099999999999999999999999999999999999999999999999999999999999999999999999999999999");

        // 加减乘除(不能直接用+、-、*、/)
        BigInteger add = bigInteger.add(bigInteger2);
        System.out.println("加=" + add);

        BigInteger subtract = bigInteger.subtract(bigInteger2);
        System.out.println("减=" + subtract);

        BigInteger multiply = bigInteger.multiply(bigInteger2);
        System.out.println("乘=" + multiply);

        BigInteger divide = bigInteger.divide(bigInteger2);
        System.out.println("除=" + divide);
    }
}

BigDecimal_.java

java
package com.hspedu.bignum;

import java.math.BigDecimal;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class BigDecimal_ {
    public static void main(String[] args) {
        // double 精度不够的场景
        double d = 1999.11111111111999999999999977788d;
        System.out.println(d);

        BigDecimal bigDecimal = new BigDecimal("1999.11");
        BigDecimal bigDecimal2 = new BigDecimal("3");

        // 加减乘
        System.out.println("加=" + bigDecimal.add(bigDecimal2));
        System.out.println("减=" + bigDecimal.subtract(bigDecimal2));
        System.out.println("乘=" + bigDecimal.multiply(bigDecimal2));

        // 除法(需指定精度,避免无限循环小数)
        System.out.println("除=" + bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));
    }
}

第588页

13.11 日期类

第一代日期类

核心类

  1. Date:精确到毫秒,代表特定的瞬间
  2. SimpleDateFormat:格式和解析日期的类,支持格式化(日期->文本)、解析(文本->日期)

格式字母表

字母日期或时间元素表示示例
GEra 标志符TextAD
yYear1996;96
M年中的月份MonthJuly; Jul; 07
w年中的周数Number27
W月份中的周数Number2
D年中的天数Number189
d月份中的天数Number10
F月份中的星期Number2
E星期中的天数TextTuesday; Tue
aAm/pm 标记TextPM
H一天中的小时数(0-23)Number0
k一天中的小时数(1-24)Number24
Kam/pm 中的小时数(0-11)Number0
ham/pm 中的小时数(1-12)Number12

Date01.java

java
package com.hspedu.date_;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Date01 {
    public static void main(String[] args) throws ParseException {
        // 1. 获取当前系统时间
        Date d1 = new Date();
        System.out.println("d1=" + d1);

        // 2. 通过指定毫秒数得到时间
        Date d2 = new Date(9234567);
        System.out.println("d2=" + d2);

        // 3. 格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
        String format = sdf.format(d1);
        System.out.println("当前日期=" + format);

        // 4. 解析文本为日期
        String s = "1996年01月01日10:20:30 星期一";
        Date parse = sdf.parse(s);
        System.out.println("parse=" + sdf.format(parse));
    }
}

第591页

第二代日期类:Calendar

基本介绍

Calendar 类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。

Calendar_.java

java
package com.hspedu.date_;

import java.util.Calendar;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Calendar_ {
    public static void main(String[] args) {
        // 1. 获取Calendar实例(抽象类,通过getInstance获取)
        Calendar c = Calendar.getInstance();

        // 2. 获取日历字段
        System.out.println("年:" + c.get(Calendar.YEAR));
        System.out.println("月:" + (c.get(Calendar.MONTH) + 1));// 月份从0开始,需+1
        System.out.println("日:" + c.get(Calendar.DAY_OF_MONTH));
        System.out.println("小时(12小时制):" + c.get(Calendar.HOUR));
        System.out.println("小时(24小时制):" + c.get(Calendar.HOUR_OF_DAY));
        System.out.println("分钟:" + c.get(Calendar.MINUTE));
        System.out.println("秒:" + c.get(Calendar.SECOND));

        // 3. 自定义格式化输出
        System.out.println(c.get(Calendar.YEAR) + "-" + (c.get(Calendar.MONTH) + 1) + "-" +
                c.get(Calendar.DAY_OF_MONTH) + " " + c.get(Calendar.HOUR_OF_DAY) + ":" +
                c.get(Calendar.MINUTE) + ":" + c.get(Calendar.SECOND));
    }
}

第592页

第三代日期类(JDK8+)

前两代日期类的不足

  1. 可变性:像日期和时间这样的类应该是不可变的
  2. 偏移性:Date中的年份是从1900开始的,而月份都从0开始
  3. 格式化:格式化只对Date有用,Calendar则不行
  4. 线程不安全,不能处理闰秒

核心类

类名说明
LocalDate只包含日期(年月日)
LocalTime只包含时间(时分秒)
LocalDateTime包含日期+时间(年月日时分秒)
DateTimeFormatter格式日期类(类似SimpleDateFormat)
Instant时间戳(类似Date)

LocalDate_.java

java
package com.hspedu.date_;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class LocalDate_ {
    public static void main(String[] args) {
        // 1. 获取当前日期时间
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println("当前日期时间=" + ldt);

        // 2. 格式化
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = dateTimeFormatter.format(ldt);
        System.out.println("格式化的日期=" + format);

        // 3. 获取单独字段
        System.out.println("年=" + ldt.getYear());
        System.out.println("月=" + ldt.getMonth());// 英文月份
        System.out.println("月=" + ldt.getMonthValue());// 数字月份
        System.out.println("日=" + ldt.getDayOfMonth());
        System.out.println("时=" + ldt.getHour());
        System.out.println("分=" + ldt.getMinute());
        System.out.println("秒=" + ldt.getSecond());

        // 4. 单独获取日期或时间
        LocalDate now = LocalDate.now();// 年月日
        LocalTime now2 = LocalTime.now();// 时分秒
        System.out.println("当前日期=" + now);
        System.out.println("当前时间=" + now2);

        // 5. 时间加减
        LocalDateTime localDateTime = ldt.plusDays(890);
        System.out.println("890 天后=" + dateTimeFormatter.format(localDateTime));

        LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
        System.out.println("3456 分钟前日期=" + dateTimeFormatter.format(localDateTime2));
    }
}

第595页

DateTimeFormatter 演示

java
// 自定义格式
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH小时mm分钟ss秒");
LocalDateTime ldt = LocalDateTime.now();
String strDate = dtf.format(ldt);
System.out.println(strDate);

Instant 时间戳

java
package com.hspedu.date_;

import java.time.Instant;
import java.util.Date;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Instant_ {
    public static void main(String[] args) {
        // 1. 获取当前时间戳
        Instant now = Instant.now();
        System.out.println(now);

        // 2. Instant -> Date
        Date date = Date.from(now);

        // 3. Date -> Instant
        Instant instant = date.toInstant();
        System.out.println(instant);
    }
}

第597页

第三代日期类更多方法

  • MonthDay类:检查重复事件
  • isLeapYear():判断是否是闰年
  • plusXxx():增加日期的某个部分
  • minusXxx():减少日期的某个部分

13.12 本章作业

编程题 Homework01.java

题目:将字符串中指定部分进行反转。比如将"abcdef"反转为"aedcbf" 要求:编写方法public static String reverse(String str,int start,int end)搞定

编程题 Homework02.java(10min)

题目:输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象 要求

  1. 用户名长度为2或3或4
  2. 密码的长度为6,要求全是数字(isDigital)
  3. 邮箱中包含@和.并且@在.的前面

编程题 Homework03.java

题目

  1. 编写java程序,输入形式为:Han shun Ping的人名,以Ping, Han.S的形式打印出来。其中.S是中间单词的首字母。
  2. 例如输入"Willian Jefferson Clinton",输出形式为:Clinton, Willian.J

编程题 Homework04.java(5min)

题目:输入字符串,判断里面有多少个大写字母,多少个小写字母,多少个数字